﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="DataRowCompare.cs" company="SmartPlan">
//   SmartPlan 2011
// </copyright>
// <summary>
//   The data row compare.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace DbDiff.Common.Comparer
{
    using System;
    using System.Data;
    using DataAccess;
    using Helper;
    using Model;

    /// <summary>
    /// The data row compare.
    /// </summary>
    public class DataRowCompare
    {
        #region constructor
        /// <summary>
        /// Initializes a new instance of the <see cref="DataRowCompare"/> class. 
        /// DataRow Compare for tables/indexes/foreigns etc.
        /// </summary>
        /// <param name="errorMessageTables">
        /// Errormessages dataset
        /// </param>
        /// <param name="dataSetDiff">
        /// Dataset diff
        /// </param>
        /// <param name="databaseInfoBase">
        /// Database objects
        /// </param>
        /// <param name="regForTextCompare">
        /// The reg For Text Compare.
        /// </param>
        public DataRowCompare(ErrorMessageTables errorMessageTables, DataSetDiff dataSetDiff, DatabaseInfoBase databaseInfoBase, RegMatch regForTextCompare)
        {
            this.ErrorMessageTables = errorMessageTables;
            this.DtDiff = dataSetDiff;
            this.DatabaseInfoBase = databaseInfoBase;
            this.RegMatch = regForTextCompare;
        }
        #endregion

        #region properties
        
        /// <summary>
        /// Gets or sets the error msg datatables.
        /// </summary>
        protected ErrorMessageTables ErrorMessageTables { get; set; }

        /// <summary>
        /// Gets or sets dataset diff
        /// </summary>
        protected DataSetDiff DtDiff { get; set; }

        /// <summary>
        ///  Gets or sets the DatabaseInfoBase obj.
        /// </summary>
        protected DatabaseInfoBase DatabaseInfoBase { get; set; }

        /// <summary>
        /// Gets or sets the reg match.
        /// </summary>
        protected RegMatch RegMatch { get; set; }

        #endregion

        /// <summary>
        /// Compare 2 rows
        /// </summary>
        /// <param name="row1">
        /// The first row
        /// </param>
        /// <param name="row2">
        /// The second row
        /// </param>
        /// <param name="objectType">
        /// The object type
        /// </param>
        /// <param name="startfrom">
        /// start from this property
        /// </param>
        /// <param name="owner">
        /// table owner for logging
        /// </param>
        /// <param name="name">
        /// table name for logging
        /// </param>
        /// <param name="field">
        /// table field for logging
        /// </param>
        /// <param name="indexName">
        /// index name for logging (can be empty)
        /// </param>
        /// <param name="objectId">
        /// The table id
        /// </param>
        /// <returns>
        /// The compared row.
        /// </returns>
        public virtual string CompareRow(
                                        DataRow row1, 
                                         DataRow row2, 
                                         DatabaseObjectTypes objectType, 
                                         int startfrom, 
                                         string owner, 
                                         string name, 
                                         string field, 
                                         string indexName, 
                                         int objectId)
        {
            string errorMessages = string.Empty;

            /*DataTable dtb = new DataTable("CompareRow");
            DataColumn[] dc = new DataColumn[row1.Table.Columns.Count];
            row1.Table.Columns.CopyTo(dc, 0);
            dtb.Columns.AddRange(dc);            
            dtb.ImportRow(row1);
            dtb.ImportRow(row2);
            cmptxt = "Compare Row:" + SerializationHelper.XmlSerialize(dtb) ;

            Logger.Instance.Write(cmptxt, LogEventType.Info*/

            int objType = this.ErrorMessageTables.FindIndexByName(DatabaseObjectDictionary.ObjectTypes[objectType]);

            if (objType < 0)
            {
                throw new ApplicationException(string.Format("There is no table named {0}", DatabaseObjectDictionary.ObjectTypes[objectType]));
            }

            // properties must be compare and 2 properties not equals
            // so for example on the form unchecked field nullable checking
            // we will not compare the fields
            // BUGBUG: we need some cases for example defaults, and calculated fields
            // that we have to remove white spaces and remarks and others for
            // stored porcedures,views,functions and triggers
            // BUGBUG WHITESPACE etc
            for (int j = startfrom; j < row1.Table.Columns.Count; j++)
                {
                    if ((row1.Table.Columns[j].Caption == ComparererConstraint.Caption) || 
                        this.CompareString(Convert.ToString(row1[j]), Convert.ToString(row2[j]), false, this.DatabaseInfoBase.DatabaseDataSets.CaseSensitive))
                    {
                        continue;
                    }

                    if (this.ErrorMessageTables.Tables[objType].Columns.Contains(row1.Table.Columns[j].ColumnName))
                    {
                        errorMessages += (errorMessages != string.Empty ? "," : string.Empty) + this.ErrorMessageTables.Tables[objType].Columns[row1.Table.Columns[j].ColumnName].Caption;
                    }
                    else
                    {
                        errorMessages += (errorMessages != string.Empty ? "," : string.Empty) + "Not specified error message!";
                    }

                    this.DtDiff.dbDiffDetails.AdddbDiffDetailsRow(
                        owner, 
                        name, 
                        field, 
                        indexName, 
                        this.ErrorMessageTables.Tables[objType].Columns[row1.Table.Columns[j].ColumnName].ColumnName, 
                        this.ErrorMessageTables.Tables[objType].Columns[row1.Table.Columns[j].ColumnName].Caption, 
                        objectId, 
                        Convert.ToString(row1[j] ?? "null"),
                        Convert.ToString(row2[j] ?? "null"), 
                        objectType.ToString());
                }

            return errorMessages;
        }

        /// <summary>
        /// Compare 2 string
        /// </summary>
        /// <param name="s1">
        /// first string
        /// </param>
        /// <param name="s2">
        /// second string
        /// </param>
        /// <param name="commandTextSimple">
        /// true then remove whitespace, comments etc.
        /// </param>
        /// <param name="caseSensitive">
        /// Text is case sensitive
        /// </param>
        /// <returns>
        /// The compare string.
        /// </returns>
        protected virtual bool CompareString(string s1, string s2, bool commandTextSimple, bool caseSensitive)
        {
            // Because of: actualy just 2 properties like Ansinulls etc
            if (commandTextSimple)
            {
                s1 = this.CommandTextSimpl(s1, caseSensitive);
                s2 = this.CommandTextSimpl(s2, caseSensitive);
            }

            return caseSensitive
                       ? s1.GetHashCode() == s2.GetHashCode()
                       : s1.ToLower().GetHashCode() == s2.ToLower().GetHashCode();
        }

        /// <summary>
        /// The command text simpl.
        /// </summary>
        /// <param name="forNormalize">
        /// The string for normalite
        /// </param>
        /// <param name="caseSensitive">
        /// The case sensitive.
        /// </param>
        /// <returns>
        /// TThe normalized string
        /// </returns>
        protected virtual string CommandTextSimpl(string forNormalize, bool caseSensitive)
        {
            forNormalize = this.RegMatch.Replace(forNormalize);

            return caseSensitive == false ? forNormalize.ToLower() : forNormalize;
        }
    }
}